package com.leo.tool.des;

import java.security.Key;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;

/**
 * 3DES加密
 * 使用Base64编码
 * 
 * @author Leo
 * @date 2019/08/13
 */
public class DESUtil {

    // 密钥算法
    public static final String KEY_ALGORITHM = "DESede";

    // Java 6支持秘钥长度为112位和168位；bouncy Castle支持秘钥为128位和192位
    private static int KEY_SIZE = 168;

    // 加解密算法/工作模式/填充方式 java6支持PKCS5Padding bouncy Castle支持PKCS7Padding
    public static final String CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding";
    
    public static void main(String[] args) throws Exception {
        String keyString = generateKeyString();
        Key key = loadKey(keyString);
        
        // 加解密
        String content = "hello world!";
        byte[] encryptData = encrypt(key, content.getBytes());
        String decryptData = new String(decrypt(key, encryptData));
        System.out.println(content.equals(decryptData));
    }
    
    public static byte[] generateKey() throws Exception {
        KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
        kg.init(KEY_SIZE);
        SecretKey generateKey = kg.generateKey();
        return generateKey.getEncoded();
    }
    
    public static String generateKeyString() throws Exception {
        return Base64.getEncoder().encodeToString(generateKey());
    }

    public static Key loadKey(String base64Key) throws Exception {
        byte[] buffer = Base64.getDecoder().decode(base64Key);
        DESedeKeySpec dks = new DESedeKeySpec(buffer);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
        return keyFactory.generateSecret(dks);
    }

    public static byte[] encrypt(Key key, byte[] plainTextData) throws Exception {
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(plainTextData);
    }

    public static byte[] decrypt(Key key, byte[] cipherData) throws Exception {
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(cipherData);
    }
    
}
